/**
 * Copyright(c) 2013 Jade Techonologies Co., Ltd.
 *
 * History:
 *   14-7-31 下午1:25 Created by dwzhang
 */
package com.jade.framework.base.comm.handler;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.jade.framework.base.comm.*;

/**
 * 采用线程池实现的协议处理器，让业务处理和协议的读写使用不同的线程。
 *
 * @author dwzhang
 * @version 1.0 14-7-31 下午1:25
 */
public class ExecutorProtocolHandler
        implements ClientProtocolHandler, ServerProtocolHandler
{
    protected ExecutorService executor;
    protected ProtocolHandler protocolHandler;
    protected int threadCount = 10;

    public void setService(ExecutorService executor)
    {
        this.executor = executor;
    }

    public void setExecutor(ExecutorService executor)
    {
        this.executor = executor;
    }

    public void setThreadCount(int threadCount)
    {
        this.threadCount = threadCount;
    }

    protected ExecutorService getExecutor()
    {
        if (executor == null) {
            synchronized (this) {
                if (executor == null) {
                    executor = Executors.newFixedThreadPool(threadCount);
                }
            }
        }
        return executor;
    }

    public void setProtocolHandler(ProtocolHandler protocolHandler)
    {
        this.protocolHandler = protocolHandler;
    }

    public void bind(ProtocolSession session)
            throws CommException, InterruptedException
    {
        if (protocolHandler instanceof ClientProtocolHandler) {
            ((ClientProtocolHandler) protocolHandler).bind(session);
        }
    }

    public void onBind(ProtocolSession session, Object bindMsg)
    {
        if (protocolHandler instanceof ServerProtocolHandler) {
            ((ServerProtocolHandler) protocolHandler).onBind(session, bindMsg);
        }
    }

    public void received(ProtocolSession session, Object message)
    {
        getExecutor().execute(new MessageRunnalbe(session, message, Event.RECEIVED));
    }

    public void connected(ProtocolSession session)
    {
        getExecutor().execute(new MessageRunnalbe(session, Event.CONNECTED));
    }

    public void idle(ProtocolSession session)
    {
        getExecutor().execute(new MessageRunnalbe(session, Event.IDLE));
    }

    public void disconnected(ProtocolSession session)
    {
        getExecutor().execute(new MessageRunnalbe(session, Event.DISCONNECTED));
    }

    public void caught(ProtocolSession session, Throwable t)
    {
        getExecutor().execute(new MessageRunnalbe(session, t, Event.CAUGHT));
    }

    enum Event
    {
        CONNECTED, DISCONNECTED, RECEIVED, CAUGHT, IDLE
    }

    protected class MessageRunnalbe
            implements Runnable
    {
        protected ProtocolSession session;
        protected Object message;
        protected Event event;
        protected Throwable cause;

        public MessageRunnalbe(ProtocolSession session, Event event)
        {
            this.session = session;
            this.event = event;
        }

        public MessageRunnalbe(ProtocolSession session, Object message, Event event)
        {
            this.session = session;
            this.message = message;
            this.event = event;
        }

        public MessageRunnalbe(ProtocolSession session, Throwable t, Event event)
        {
            this.session = session;
            this.cause = t;
            this.event = event;
        }

        public void run()
        {
            if (event == Event.CONNECTED) {
                protocolHandler.connected(session);
            }
            else if (event == Event.DISCONNECTED) {
                protocolHandler.disconnected(session);
            }
            else if (event == Event.IDLE) {
                protocolHandler.idle(session);
            }
            else if (event == Event.RECEIVED) {
                protocolHandler.received(session, message);
            }
            else if (event == Event.CAUGHT) {
                protocolHandler.caught(session, cause);
            }
        }
    }
}
